--by Dusan

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;

use work.reg_file_pkg.all;

entity reg_file is
	
	generic (
	  num_wr_ports : integer := 3;
	  num_rd_ports  : integer := 4;
	  num_bidir_ports : integer := 0
	);

	port
	(
		-- Input ports
		wrEnable	: in std_logic_vector(((num_wr_ports-1) + num_bidir_ports) downto 0);
		data_in	: in data_pin_array(0 to 2);
		wr_addr	: in addr_pin_array(0 to 2);
		rd_addr 	: in addr_pin_array(0 to 3);
		clk		: in std_logic;
		rst		: in std_logic;
		
		-- Output ports
		data_out	: out data_pin_array(0 to 3)
	);
end reg_file;


architecture arch of reg_file is
	
	constant depth			:	integer	:=	32;
	constant data_width	:	integer	:=	32;
	
	constant num_in_ports 	: integer := num_wr_ports + num_bidir_ports;
	constant num_out_ports 	: integer := num_rd_ports + num_bidir_ports;

	type regFile_t is array (0 to depth-1) of std_logic_vector(data_width-1 downto 0);
		
	signal regs_reg, regs_next : regFile_t;
	
	function init return regFile_t is
		variable ret : regFile_t;
	begin
		for i in ret'range loop
			ret(i) := (others => '0');
		end loop;
		
		return ret;
	end function init;
	
begin
	chngReg: process (clk, rst) is
	begin
		if (rst = '1') then
			regs_reg <= init;
		elsif (rising_edge(clk)) then
			for i in 0 to depth-1 loop
				regs_reg(i) <= regs_next(i);
			end loop;
		end if;
	end process chngReg;
	
	newValue: process (regs_reg, wrEnable, data_in, wr_addr, rd_addr) is	
	begin
		regs_next <= regs_reg;
	
		--Read registers
		for i in 0 to num_out_ports-1 loop
			if (is_X(rd_addr(i))) then
				data_out(i) <= (others => 'X');
			else
				data_out(i) <= regs_reg(to_integer(unsigned(rd_addr(i))));
			end if;
		end loop;
		
		--Write registers
		for i in 0 to num_in_ports-1 loop
			if (wrEnable(i) = '1') then
				regs_next(to_integer(unsigned(wr_addr(i)))) <= data_in(i);	--Write
				for j in 0 to num_out_ports-1 loop
					if rd_addr(j) = wr_addr(i) then
						data_out(j) <= data_in(i);
					end if;
				end loop;
			end if;
		end loop;
	end process newValue;
end arch;


